
// 定义 blog 结构体
pub struct Post {
    state: Option<Box<State>>,
    content: String,
}
// 定义blog的方法 一般不带pub前缀
impl Post {
    pub fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new(),
        }
    }
}
// 另一个blog方法定义块，编译器会组合两个块的代码
impl Post {
    // --snip--
    pub fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
    // 填写内容
    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    // 返回内容
    pub fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(&self)
    }
    // 请求显示
    pub fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }
}
// 定义状态的特性（trait） 
trait State {
    fn request_review(self: Box<Self>) -> Box<State>; // 请求审核
    fn approve(self: Box<Self>) -> Box<State>; // 同意
    fn content<'a>(&self, _post: &'a Post) -> &'a str { // 这是定义了默认实现的 trait方法
        ""
    }
}
// 定义结构体 draft 草稿态
struct Draft {}
// 草稿态实现了 state 特性
impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<State> {
        Box::new(PendingReview {})
    }
    // 草台态的 同意 是无意义的，不做处理，只是原样返回状态值
    fn approve(self: Box<Self>) -> Box<State> {
        self
    }
    // content调用了默认的实现content
}
// 定义 待审核 态
struct PendingReview {}
// 待审核态 实现了 状态特性
impl State for PendingReview {
    // 待审核态 的请求审核就无意义的，所以原样返回状态
    fn request_review(self: Box<Self>) -> Box<State> {
        self
    }
    // 待审核的 同意 就有意义了，返回下一个状态
    fn approve(self: Box<Self>) -> Box<State> {
        Box::new(Published {})
    }
    // content调用了默认的实现content
}
// 定义发布态 结构体
struct Published {}
// 实现发布态 的 状态 特性处理
impl State for Published {
    // 发布态 的 请求审核无意义，原样返回状态
    fn request_review(self: Box<Self>) -> Box<State> {
        self
    }
    // 发布态的 同意 也无意义（因为已经同意过了）原样返回状态值
    fn approve(self: Box<Self>) -> Box<State> {
        self
    }
    // 发布态 内容 就能返回其真实值了
    fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content
    }
}










#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
